use std::path::{Path, PathBuf};

use axum::{Router, extract::State, routing::post, Json};
use axum_ifnk_common::{app_error, prelude::{AppError, Response}};
use serde::Deserialize;
use utoipa::ToSchema;

use crate::{
    AppState,
    domain::{
        DisplayConfig, ScaleData, StationAudio, StationAudioView,
        StationInfo, WindowConfig,
    },
    services::{BinFileScanner, NodeConfService, downsample_service},
};

pub fn routes() -> Router<AppState> {
    Router::new().route("/station-audio/generate", post(generate_station_audio_view))
}

#[derive(Debug, Deserialize, ToSchema)]
pub struct GenerateStationAudioRequest {
    pub project_id: i32,
}

/// 生成测站波形视图
///
/// 根据项目ID生成所有测站的波形数据，包含：
/// - 每个测站的配置和文件列表
/// - 降采样后的波形数据（前120秒，2000个点）
#[utoipa::path(
    post,
    path = "/station-audio/generate",
    request_body = GenerateStationAudioRequest,
    responses(
        (status = 200, description = "波形视图生成成功", body = Response<StationAudioView>),
        (status = 404, description = "项目不存在"),
        (status = 500, description = "服务器内部错误")
    ),
    tag = "声波历史"
)]
async fn generate_station_audio_view(
    State(state): State<AppState>,
    Json(request): Json<GenerateStationAudioRequest>,
) -> Result<Response<StationAudioView>, AppError> {
    // 1. 查询项目信息
    let project = state
        .json_data_service
        .get_project_by_id(request.project_id)
        .map_err(|err| app_error!(500, "读取项目信息失败: {}", err))?
        .ok_or_else(|| app_error!(404, "项目 {} 不存在", request.project_id))?;

    // 2. 拼接项目路径
    let project_path = PathBuf::from(&project.data_directory).join(&project.project_name);
    if !project_path.exists() {
        return Err(app_error!(
            404,
            "项目路径不存在: {}",
            project_path.display()
        ));
    }

    // 3. 读取测站配置
    let node_confs = NodeConfService::read_nodes_config(&project_path)
        .map_err(|err| app_error!(500, "读取测站配置失败: {}", err))?;

    if node_confs.is_empty() {
        return Err(app_error!(404, "项目中未找到测站配置"));
    }

    // 4. 处理每个测站
    let mut station_audios = Vec::with_capacity(node_confs.len());
    let mut scale_datas = Vec::with_capacity(node_confs.len());
    let mut window_start_time = f64::MAX;
    let mut window_end_time = f64::MIN;

    for (index, node_conf) in node_confs.iter().enumerate() {
        // 4a. 确定测站文件夹路径
        let folder_name = NodeConfService::get_station_folder_name(&project_path, node_conf);
        let station_folder = project_path.join(&folder_name);

        if !station_folder.exists() {
            tracing::warn!(
                "测站文件夹不存在，跳过: {} (boardid={})",
                station_folder.display(),
                node_conf.boardid
            );
            continue;
        }

        // 4b. 扫描 bin 文件
        let time_scopes = BinFileScanner::scan_bin_files(
            &station_folder,
            node_conf.smprate as usize,
            node_conf.channels as usize,
            node_conf.depth(),
        )
        .map_err(|err| {
            app_error!(
                500,
                "扫描测站 {} 的 bin 文件失败: {}",
                node_conf.boardid,
                err
            )
        })?;

        if time_scopes.is_empty() {
            tracing::warn!(
                "测站 {} 未找到有效的 bin 文件",
                node_conf.boardid
            );
            continue;
        }

        // 4c. 找到第一个有效的 bin 文件
        let first_file = time_scopes
            .iter()
            .find(|scope| !scope.is_empty)
            .ok_or_else(|| {
                app_error!(
                    404,
                    "测站 {} 没有有效的音频数据",
                    node_conf.boardid
                )
            })?;

        // 4d. 读取前 120 秒的数据
        let duration = 120.0_f64.min(first_file.duration);
        let file_path = Path::new(&first_file.file_path);

        let wave_data = state
            .sound_wave_reader
            .read_sound_wave_data_by_channel(
                file_path,
                node_conf.smprate as u32,
                node_conf.channels as usize,
                node_conf.depth() as u32,
                "signed",
                0.0,
                duration,
                1, // 固定使用第一个通道
                node_conf.cvt_coef.unwrap_or(1.0) as f32,
                node_conf.ranges.first().copied().unwrap_or(1.0) as f32,
                false,
            )
            .map_err(|err| {
                app_error!(
                    500,
                    "读取测站 {} 的音频数据失败: {}",
                    node_conf.boardid,
                    err
                )
            })?;

        // 4e. 降采样到 2000 个点
        let downsampled = downsample_service::downsample_min_max(&wave_data.data);

        // 4f. 计算 min/max 值
        let (min_value, max_value) = if downsampled.is_empty() {
            (-1.0, 1.0)
        } else {
            let min = downsampled
                .iter()
                .copied()
                .fold(f32::INFINITY, f32::min);
            let max = downsampled
                .iter()
                .copied()
                .fold(f32::NEG_INFINITY, f32::max);
            (min, max)
        };

        // 4g. 创建 StationInfo
        let station_info = StationInfo {
            config: node_conf.clone(),
            folder_path: Some(station_folder.to_string_lossy().to_string()),
            is_modified: false,
            seismic_start_time: None,
            is_online: false,
            last_heartbeat_time: None,
            can_collect: false,
            id: node_conf.boardid,
        };

        // 4h. 创建 DisplayConfig
        let display_config = DisplayConfig {
            display: true,
            order: index as i32,
            selected_channel: 1,
            max_value,
            min_value,
        };

        // 4i. 更新窗口时间范围
        let start_time = first_file.start_time;
        let end_time = start_time + duration;
        window_start_time = window_start_time.min(start_time);
        window_end_time = window_end_time.max(end_time);

        // 4j. 组装 StationAudio
        let station_audio = StationAudio {
            display_config,
            time_scope_list: time_scopes,
            station_info,
        };

        station_audios.push(station_audio);

        // 4k. 组装 ScaleData
        let scale_data = ScaleData {
            boardid: node_conf.boardid,
            list: downsampled,
        };

        scale_datas.push(scale_data);
    }

    // 5. 检查是否有有效数据
    if station_audios.is_empty() {
        return Err(app_error!(404, "项目中没有有效的测站数据"));
    }

    // 6. 创建窗口配置
    let window_duration = window_end_time - window_start_time;
    let window_config = WindowConfig {
        current_window_start_time: window_start_time,
        current_window_end_time: window_end_time,
        current_window_duration: window_duration,
    };

    // 7. 组装最终结果
    let view = StationAudioView {
        station_audios,
        scale_datas,
        window_config,
    };

    Ok(Response::success(view))
}
